home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Snippets / Sound / SndPlayDoubleBuffer / _source / Private_DBFFFunctions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-15  |  20.6 KB  |  625 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routines demonstrating how to set up for using SndPlayDoubleBuffer.
  5. **
  6. **    by Mark Cookson, Apple Developer Technical Support
  7. **
  8. **    File:    Private_DBFFFunctions.c
  9. **
  10. **    Copyright ©1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "Apple Sample
  17. **    Code" after having made changes. If you're going to re-distribute the
  18. **    source, we require that you make it clear in the source that the code
  19. **    was descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include "Private_DBFFFunctions.h"
  23.  
  24. /********************************************************************************************
  25.         ** YOU SHOULD NEVER NEED TO CALL ANY OF THE FOLLOWING ROUTINES DIRECTLY **
  26. ********************************************************************************************/
  27.  
  28. /*    Purpose:        This sets all of local and global variables to safe values.
  29.                     This routine is called by ASoundNew, and is    called by the
  30.                     ASoundDone function after it has cleaned up to reset things.
  31.     Side Effects:    None.
  32. */
  33. /*-----------------------------------------------------------------------*/
  34.         OSErr    ASoundInit        (SoundInfoPtr theSoundInfo)
  35. /*-----------------------------------------------------------------------*/
  36. {
  37.     NumVersion    SndManagerVer;
  38.     OSErr        theErr            = noErr;
  39.  
  40.     theSoundInfo->globals.gSupports16Bit    = true;
  41.     theSoundInfo->globals.gSupportsSPDB        = true;
  42.  
  43.     theSoundInfo->signature            = kDBFFSignature;
  44.     theSoundInfo->chan                = kInit;
  45.     theSoundInfo->rateForResume        = kInit;
  46.     /* create a Universal Procedure Pointer (UPP) for our sound callback */
  47.     theSoundInfo->theSoundCallBackUPP = NewSndCallBackProc(ASoundDoneCallBack);
  48.     theSoundInfo->fileType            = kInit;
  49.     (void)ASoundSetNumBuffers        (theSoundInfo, kStart);
  50.     theSoundInfo->dataStart            = kInit;
  51.     (void)ASoundSetSoundLength        (theSoundInfo, kInit);
  52.     ASoundSetBytesCopied            (theSoundInfo, kInit);
  53.     ASoundSetCurBuffer                (theSoundInfo, kStart);
  54.     (void)ASoundSetBufferSize        (theSoundInfo, kInit);
  55.     theSoundInfo->bytesPerFrame        = kInit;
  56.     theSoundInfo->refNum            = kInit;
  57.     theSoundInfo->vRefNum            = nil;
  58.     theSoundInfo->compFactor        = kNoCompression;
  59.     theSoundInfo->paused            = false;
  60.     theSoundInfo->playing            = false;
  61.     theSoundInfo->adjusting            = false;
  62.     theSoundInfo->soundDone            = false;
  63.     theSoundInfo->backwards            = false;
  64.     theSoundInfo->hasBeenAdjusted    = false;
  65.     theSoundInfo->needsMasking        = false;
  66.     theSoundInfo->stopping            = false;
  67.  
  68.     SndManagerVer = SndSoundManagerVersion ();
  69.     theErr = InterrogateSystem (&(theSoundInfo->globals));
  70.     if (theErr == noErr) {
  71.         if (SndManagerVer.majorRev >= kMinSndMgrVer) {
  72.             if ((theSoundInfo->globals.ggestaltSoundAttr & (1 << gestaltSndPlayDoubleBuffer)) == false) {
  73.                 DebugPrint ("\pSndPlayDoubleBuffer isn't supported!");
  74.                 theSoundInfo->globals.gSupportsSPDB = false;
  75.                 theErr = kNoSPDBErr;
  76.             }
  77.             if ((theSoundInfo->globals.ggestaltSoundAttr & (1<< gestalt16BitAudioSupport)) == false) {
  78.                 DebugPrint ("\pThis machine doesn't support 16 bit audio!");
  79.                 theSoundInfo->globals.gSupports16Bit = false;
  80.                 theErr = notEnoughHardwareErr;    /* This doesn't have to be a fatal error */
  81.             }
  82.         }
  83.         else {
  84.             theErr = kOldSndMgrErr;
  85.         }
  86.     }
  87.     else {
  88.         theErr = kInitErr;
  89.     }
  90.  
  91.     return theErr;
  92. }
  93.  
  94. /*-----------------------------------------------------------------------*/
  95. Boolean            IsValid                    (SoundInfoPtr theSoundInfo)
  96. /*-----------------------------------------------------------------------*/
  97. {
  98.     return CheckValididity (theSoundInfo, false);
  99. }
  100.  
  101. /*-----------------------------------------------------------------------*/
  102. Boolean            StrictIsValid            (SoundInfoPtr theSoundInfo)
  103. /*-----------------------------------------------------------------------*/
  104. {
  105.     return CheckValididity (theSoundInfo, true);
  106. }
  107.  
  108.  
  109. /*-----------------------------------------------------------------------*/
  110. Boolean            CheckValididity            (SoundInfoPtr theSoundInfo,
  111.                                         Boolean strict)
  112. /*-----------------------------------------------------------------------*/
  113. {
  114.     Boolean        returnValue        = true;        /* Assume success */
  115.  
  116.     if (theSoundInfo == nil) {
  117.         returnValue = false;
  118.     }
  119.     else {
  120.         if (strict == true) {
  121.             if (theSoundInfo->signature != kDBFFSignature) {
  122.                 returnValue = false;
  123.                 DebugPrint ("\pStrictIsValid theSoundInfo->signature is invalid");
  124.             }
  125.             else {
  126.                 if (theSoundInfo->doubleHeader.dbhNumChannels <= kInit) {
  127.                     returnValue = false;
  128.                     DebugPrint ("\pStrictIsValid theSoundInfo->doubleHeader.dbhNumChannels is invalid");
  129.                 }
  130.                 if (theSoundInfo->doubleHeader.dbhSampleSize <= kInit) {
  131.                     returnValue = false;
  132.                     DebugPrint ("\pStrictIsValid theSoundInfo->doubleHeader.dbhSampleSize is invalid");
  133.                 }
  134.                 if (theSoundInfo->doubleHeader.dbhPacketSize < kInit) {
  135.                     returnValue = false;
  136.                     DebugPrint ("\pStrictIsValid theSoundInfo->doubleHeader.dbhPacketSize is invalid");
  137.                 }
  138.                 if (theSoundInfo->theSoundCallBackUPP == nil) {
  139.                     returnValue = false;
  140.                     DebugPrint ("\pStrictIsValid theSoundInfo->theSoundCallBackUPP is invalid");
  141.                 }
  142.                 if (theSoundInfo->rateForResume < kInit) {
  143.                     returnValue = false;
  144.                     DebugPrint ("\pStrictIsValid theSoundInfo->rateForResume is invalid");
  145.                 }
  146.                 if (theSoundInfo->numBuffers <= kInit) {
  147.                     returnValue = false;
  148.                     DebugPrint ("\pStrictIsValid theSoundInfo->numBuffers is invalid");
  149.                 }
  150.                 if (theSoundInfo->dataStart < kInit) {
  151.                     returnValue = false;
  152.                     DebugPrint ("\pStrictIsValid theSoundInfo->dataStart is invalid");
  153.                 }
  154.                 if (theSoundInfo->bytesTotal <= kInit) {
  155.                     returnValue = false;
  156.                     DebugPrint ("\pStrictIsValid theSoundInfo->bytesTotal is invalid");
  157.                 }
  158.                 if (theSoundInfo->bytesCopied <= kInit) {
  159.                     returnValue = false;
  160.                     DebugPrint ("\pStrictIsValid theSoundInfo->bytesCopied is invalid");
  161.                 }
  162.                 if (theSoundInfo->currentBuffer <= kInit) {
  163.                     returnValue = false;
  164.                     DebugPrint ("\pStrictIsValid theSoundInfo->currentBuffer is invalid");
  165.                 }
  166.                 if (theSoundInfo->doubleBufferSize <= kInit) {
  167.                     returnValue = false;
  168.                     DebugPrint ("\pStrictIsValid theSoundInfo->doubleBufferSize is invalid");
  169.                 }
  170.                 if (theSoundInfo->bytesPerFrame <= kInit) {
  171.                     returnValue = false;
  172.                     DebugPrint ("\pStrictIsValid theSoundInfo->bytesPerFrame is invalid");
  173.                 }
  174.                 if (theSoundInfo->compFactor <= kInit) {
  175.                     returnValue = false;
  176.                     DebugPrint ("\pStrictIsValid theSoundInfo->compFactor is invalid");
  177.                 }
  178.             }
  179.         }
  180.         else {
  181.             if (theSoundInfo->signature != kDBFFSignature) {
  182.                 returnValue = false;
  183.                 DebugPrint ("\pIsValid theSoundInfo->signature is invalid");
  184.             }
  185.             else {
  186.                 if (theSoundInfo->doubleHeader.dbhNumChannels < kInit) {
  187.                     returnValue = false;
  188.                     DebugPrint ("\pIsValid theSoundInfo->doubleHeader.dbhNumChannels is invalid");
  189.                 }
  190.                 if (theSoundInfo->doubleHeader.dbhSampleSize < kInit) {
  191.                     returnValue = false;
  192.                     DebugPrint ("\pIsValid theSoundInfo->doubleHeader.dbhSampleSize is invalid");
  193.                 }
  194.                 if (theSoundInfo->doubleHeader.dbhPacketSize < kInit) {
  195.                     returnValue = false;
  196.                     DebugPrint ("\pIsValid theSoundInfo->doubleHeader.dbhPacketSize is invalid");
  197.                 }
  198.                 if (theSoundInfo->theSoundCallBackUPP == nil) {
  199.                     returnValue = false;
  200.                     DebugPrint ("\pIsValid theSoundInfo->theSoundCallBackUPP is invalid");
  201.                 }
  202.                 if (theSoundInfo->rateForResume < kInit) {
  203.                     returnValue = false;
  204.                     DebugPrint ("\pIsValid theSoundInfo->rateForResume is invalid");
  205.                 }
  206.                 if (theSoundInfo->numBuffers < kInit) {
  207.                     returnValue = false;
  208.                     DebugPrint ("\pIsValid theSoundInfo->numBuffers is invalid");
  209.                 }
  210.                 if (theSoundInfo->dataStart < kInit) {
  211.                     returnValue = false;
  212.                     DebugPrint ("\pIsValid theSoundInfo->dataStart is invalid");
  213.                 }
  214.                 if (theSoundInfo->bytesTotal < kInit) {
  215.                     returnValue = false;
  216.                     DebugPrint ("\pIsValid theSoundInfo->bytesTotal is invalid");
  217.                 }
  218.                 if (theSoundInfo->bytesCopied < kInit) {
  219.                     returnValue = false;
  220.                     DebugPrint ("\pIsValid theSoundInfo->bytesCopied is invalid");
  221.                 }
  222.                 if (theSoundInfo->currentBuffer < kInit) {
  223.                     returnValue = false;
  224.                     DebugPrint ("\pIsValid theSoundInfo->currentBuffer is invalid");
  225.                 }
  226.                 if (theSoundInfo->doubleBufferSize < kInit) {
  227.                     returnValue = false;
  228.                     DebugPrint ("\pIsValid theSoundInfo->doubleBufferSize is invalid");
  229.                 }
  230.                 if (theSoundInfo->bytesPerFrame < kInit) {
  231.                     returnValue = false;
  232.                     DebugPrint ("\pIsValid theSoundInfo->bytesPerFrame is invalid");
  233.                 }
  234.                 if (theSoundInfo->compFactor < kInit) {
  235.                     returnValue = false;
  236.                     DebugPrint ("\pIsValid theSoundInfo->compFactor is invalid");
  237.                 }
  238.             }
  239.         }
  240.     }
  241.  
  242.     return returnValue;
  243. }
  244.  
  245. /*
  246.     Purpose:        Called by StandardFile for every file in a folder to
  247.                     see if we want to display that file in the open file
  248.                     dialog.  Return false (don't filter) if you want the
  249.                     file displayed, true (do filter) if you don't want
  250.                     it displayed.
  251.  
  252.                     This calls ASoundCanThisPlay() which calls the header
  253.                     parsing routines.  If we can parse the header we
  254.                     should be able to play the file.
  255.     Side Effects:    None.
  256. */
  257. /*-----------------------------------------------------------------------*/
  258. pascal Boolean    ASoundFileFilter        (CInfoPBPtr theFileInfo)
  259. /*-----------------------------------------------------------------------*/
  260. {
  261.     OSErr        theErr            = noErr;
  262.     Boolean        returnValue        = true;        /* by default don't display the file */
  263.  
  264.     theErr = ASoundCanThisPlay (theFileInfo);
  265.     if (theErr == noErr) {                    /* We can play this file. */
  266.         returnValue = false;                /* Display this file */
  267.     }
  268.  
  269.     if (theErr != noErr && theErr != kUnknownFormat) {
  270.         DebugPrint ("\pError in ASoundFileFilter");
  271.     }
  272.  
  273.     return returnValue;
  274. }
  275.  
  276. /*
  277.     Purpose:        Sets how many buffers will be needed to play the entire
  278.                     sound.
  279.     Side Effects:    None.
  280. */
  281. /*-----------------------------------------------------------------------*/
  282.         OSErr    ASoundSetNumBuffers        (SoundInfoPtr theSoundInfo,
  283.                                         long newValue)
  284. /*-----------------------------------------------------------------------*/
  285. {
  286.     OSErr        theErr    = noErr;
  287.  
  288.     if (newValue >= kInit) {
  289.         theSoundInfo->numBuffers = newValue;
  290.     }
  291.     else {
  292.         theErr = kBadValue;
  293.     }
  294.  
  295.     return theErr;
  296. }
  297.  
  298. /*
  299.     Purpose:        To install a callback command into the current sound
  300.                     channel.
  301.     Side Effects:    None.
  302. */
  303. /*-----------------------------------------------------------------------*/
  304.         OSErr    InstallCallBack            (SoundInfoPtr theSoundInfo)
  305. /*-----------------------------------------------------------------------*/
  306. {
  307.     SndCommand    mycmd    = {callBackCmd, kInit, kInit};
  308.     OSErr        theErr    = noErr;
  309.  
  310.     mycmd.param2 = SetCurrentA5();
  311.     theErr = SndDoCommand (theSoundInfo->chan, &mycmd, true);
  312.  
  313.     if (theErr != noErr) {
  314.         DebugPrint ("\pError in InstallCallBack");
  315.     }
  316.  
  317.     return theErr;
  318. }
  319.  
  320. /*
  321.     Purpose:        Gather the information needed (from the sound's header)
  322.                     to setup the structures the Sound Manager will need to
  323.                     play the sound.
  324.     Side Effects:    This will allocate memory for the sound header strucure
  325.                     that will be disposed of by ASoundDonePlaying.
  326. */
  327. /*-----------------------------------------------------------------------*/
  328.         OSErr    SetUpSoundHeader        (SoundInfoPtr theSoundInfo,
  329.                                         unsigned long bufferSize)
  330. /*-----------------------------------------------------------------------*/
  331. {
  332.     long double        sampleRate    = kInit;
  333.     long            dataStart    = kInit,
  334.                     sndLength    = kInit,
  335.                     numBuffers    = kInit;
  336.     short            remainder    = kInit;
  337.     OSErr            theErr        = noErr;
  338.  
  339.     theSoundInfo->chan->userInfo = (long)theSoundInfo;        /* So we know who we are in the SoundCompletion routines */
  340.  
  341.     switch (theSoundInfo->fileType) {
  342.         case kCompressedAIFFFile:
  343.         case kUncompressedAIFFFile:
  344.             theErr = ASoundGetAIFFHeader (theSoundInfo, &dataStart, &sndLength);
  345.             break;
  346.         case kWAVEFile:
  347.         case kWAVFile:
  348.             theErr = ASoundGetWAVEHeader (theSoundInfo, &dataStart, &sndLength);
  349.             break;
  350.         case kAUFile:
  351.             theErr = ASoundGetULAWHeader (theSoundInfo, &dataStart, &sndLength);
  352.             break;
  353.         case kSNDResource:
  354.         case kResource:
  355.             theErr = ASoundGetSNDHeader  (theSoundInfo, &dataStart, &sndLength);
  356.             break;
  357.         default:
  358.             theErr = kUnknownFormat;
  359.             break;
  360.     }
  361.  
  362.     theSoundInfo->dataStart = dataStart;
  363.     if (theErr != noErr) {
  364.         DebugPrint ("\pASoundGetAIFFHeader error!");
  365.         (void)SndDisposeChannel (theSoundInfo->chan, true);
  366.     }
  367.     else {
  368.         if ((theSoundInfo->doubleHeader.dbhSampleSize == kSixteen) && (theSoundInfo->globals.gSupports16Bit == false)) {
  369.             DebugPrint ("\pThis is a 16 bit sound, this is not a 16 bit capable machine.");
  370.             theErr = notEnoughHardwareErr;
  371.         }
  372.         else {    
  373.             theErr = ASoundSetSoundLength (theSoundInfo, sndLength);
  374.             ASoundSetBytesCopied (theSoundInfo, dataStart);                /* skip the header of the file */
  375.  
  376.             sampleRate = ASoundFixToLongDouble (theSoundInfo->doubleHeader.dbhSampleRate);
  377.  
  378.             if (bufferSize > kInit) {
  379.                 theErr = ASoundSetBufferSize (theSoundInfo, bufferSize);
  380.             }
  381.             else {
  382.                 theErr = ASoundSetBufferSize (theSoundInfo, (((theSoundInfo->doubleHeader.dbhSampleSize / kBitsPerByte) * theSoundInfo->doubleHeader.dbhNumChannels * sampleRate) / kBufLen) / theSoundInfo->compFactor);
  383.             }
  384.  
  385.             if (ASoundGetBufferSize (theSoundInfo) > kInit) {
  386.                 numBuffers = (ASoundGetNumTotalBytes (theSoundInfo) / ASoundGetBufferSize (theSoundInfo));
  387.                 remainder = (ASoundGetNumTotalBytes (theSoundInfo) % ASoundGetBufferSize (theSoundInfo));
  388.                 if (remainder != 0) {    /* Is the last buffer only a partial buffer? */
  389.                     numBuffers++;        /* Don't forget to account for it! */
  390.                 }
  391.                 theErr = ASoundSetNumBuffers (theSoundInfo, numBuffers);
  392.             }
  393.             else {
  394.                 DebugPrint ("\pThe buffer size is zero, this is bad.");
  395.                 theErr = dsZeroDivErr;
  396.             }
  397.  
  398.             theSoundInfo->doubleHeader.dbhDoubleBack = NewSndDoubleBackProc (ASoundDoubleBackProc);
  399.             theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufOne] = nil;
  400.             theSoundInfo->doubleHeader.dbhBufferPtr[kDBBufTwo] = nil;
  401.         }
  402.     }
  403.  
  404.     if (theErr != noErr) {
  405.         DebugPrint ("\pError in SetUpSoundHeader");
  406.     }
  407.  
  408.     return theErr;
  409. }
  410.  
  411. /*
  412.     Purpose:        Pause the playing of the sound.
  413.     Side Effects:    None.
  414. */
  415. /*-----------------------------------------------------------------------*/
  416.         OSErr    PauseSound                (SoundInfoPtr theSoundInfo)
  417. /*-----------------------------------------------------------------------*/
  418. {
  419.     SndCommand        theCmd    = {getRateCmd, kInit, kInit};
  420.     OSErr            theErr    = noErr;
  421.  
  422.     theCmd.param2 = (long)&theSoundInfo->rateForResume;
  423.     theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  424.  
  425.     if (theErr == noErr) {
  426.         theCmd.cmd = rateCmd;
  427.         theCmd.param2 = kStopPlaying;
  428.         theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  429.         if (theErr == noErr) {
  430.             theSoundInfo->paused = true;
  431.         }
  432.     }
  433.  
  434.     if (theErr != noErr) {
  435.         DebugPrint ("\pError in PauseSound");
  436.     }
  437.  
  438.     return theErr;
  439. }
  440.  
  441. /*
  442.     Purpose:        Resume the playing of the sound.
  443.     Side Effects:    This will reinstall the sound completion callback
  444.                     if it was removed by the ASoundPauseForAdjust function.
  445. */
  446. /*-----------------------------------------------------------------------*/
  447.         OSErr    ResumeSound                (SoundInfoPtr theSoundInfo)
  448. /*-----------------------------------------------------------------------*/
  449. {
  450.     SndCommand        theCmd    = {rateCmd, kInit, kInit};
  451.     OSErr            theErr    = noErr;
  452.  
  453.     theCmd.param2 = theSoundInfo->rateForResume;
  454.     theErr = SndDoImmediate (theSoundInfo->chan, &theCmd);
  455.  
  456.     if (theErr == noErr) {
  457.         theSoundInfo->paused = false;
  458.         if (theSoundInfo->hasBeenAdjusted == true) {
  459.             theErr = SndPlayDoubleBuffer (theSoundInfo->chan, (SndDoubleBufferHeaderPtr)&(theSoundInfo->doubleHeader));
  460.             theErr = InstallCallBack (theSoundInfo);
  461.             theSoundInfo->hasBeenAdjusted = false;
  462.         }
  463.     }
  464.  
  465.     if (theErr != noErr) {
  466.         DebugPrint ("\pError in ResumeSound");
  467.     }
  468.  
  469.     return theErr;
  470. }
  471.  
  472. /*-----------------------------------------------------------------------*/
  473.         OSErr    ASoundSetBufferSize        (SoundInfoPtr theSoundInfo,
  474.                                         long newValue)
  475. /*-----------------------------------------------------------------------*/
  476. {
  477.     OSErr            theErr        = noErr;
  478.  
  479.     if (newValue >= nil) {
  480.         /* Make sure the buffer is an integer multiple of the packet size,
  481.            otherwise IMA will be VERY upset, and WAVE files might not sound
  482.            too good either. */
  483.         if (theSoundInfo->doubleHeader.dbhPacketSize > kInit) {
  484.             newValue /= theSoundInfo->doubleHeader.dbhPacketSize;
  485.         }
  486.         newValue *= theSoundInfo->doubleHeader.dbhPacketSize;
  487.         theSoundInfo->doubleBufferSize = newValue;
  488.     }
  489.     else {
  490.         theSoundInfo->doubleBufferSize = kInit;
  491.         DebugPrint ("\pBad value passed to ASoundSetBufferSize");
  492.         theErr = kBadValue;
  493.     }
  494.  
  495.     if (theErr != noErr) {
  496.         DebugPrint ("\pError in ASoundSetBufferSize");
  497.     }
  498.  
  499.     return theErr;
  500. }
  501.  
  502. /*-----------------------------------------------------------------------*/
  503.         OSErr    ASoundSetSoundLength    (SoundInfoPtr theSoundInfo,
  504.                                         long newValue)
  505. /*-----------------------------------------------------------------------*/
  506. {
  507.     OSErr            theErr        = noErr;
  508.  
  509.     if (newValue >= nil) {
  510.         theSoundInfo->bytesTotal = newValue;
  511.     }
  512.     else {
  513.         theSoundInfo->bytesTotal = kInit;
  514.         theErr = kBadValue;
  515.     }
  516.  
  517.     if (theErr != noErr) {
  518.         DebugPrint ("\pError in ASoundSetSoundLength");
  519.     }
  520.  
  521.     return theErr;
  522. }
  523.  
  524. /*
  525.     Purpose:        The purpose of this routine is to fill out the
  526.                     SndDoubleBufferHeader structure with the information the
  527.                     Sound Manager will need, and to fill out the
  528.                     myParamBlockRec structure with the information the
  529.                     ASoundDoubleBackProc interrupt routine will need.  It
  530.                     then calls ASoundDoubleBackProc to fill the first two
  531.                     buffers.
  532.     Side effects:    This routine allocates two pointers as buffers for the
  533.                     sound that will be playing.
  534.                     This routine allocates two custom paramBlockRecs for
  535.                     the ASoundDoubleBackProc (interrupt routine) to use.
  536. */
  537. /*-----------------------------------------------------------------------*/
  538.         OSErr    ASoundPrimeBuffers        (SoundInfoPtr theSoundInfo)
  539. /*-----------------------------------------------------------------------*/
  540. {
  541.     myParmBlkPtr        myPB            = nil;
  542.     SndDoubleBufferPtr    doubleBuffer    = nil;
  543.     IOCompletionUPP        myIOCompletion    = nil;
  544.     OSErr                theErr            = noErr;
  545.     short                i                = kInit;
  546.  
  547.     for (i = kInit; i <= kOne; ++i) {
  548.         if (theSoundInfo->doubleHeader.dbhBufferPtr[i] == nil) {
  549.             doubleBuffer = (SndDoubleBufferPtr)NewPtrClear (sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
  550.             if (doubleBuffer == nil || MemError() != noErr) {
  551.                 DebugPrint("\pNo memory for double buffers!");
  552.                 theErr = memFullErr;
  553.             }
  554.             else {
  555.                 /* Hold the memory in case VM is on, this will help to ensure that we have no sound
  556.                    drop outs caused by the paging of our buffers. */
  557.                 HoldMemory (doubleBuffer, sizeof(SndDoubleBuffer) + ASoundGetBufferSize (theSoundInfo));
  558.                 /* dbNumFrames gets set in the ASoundDoubleBackProc() routine */
  559.                 doubleBuffer->dbFlags = nil;
  560.                 doubleBuffer->dbUserInfo[kSndInfoPtr] = (long)theSoundInfo;        /* Make this point at our SoundInfo struct */
  561.                 myPB = (myParamBlockRec *)NewPtrClear(sizeof(myParamBlockRec));        /* Make one for each buffer so */
  562.                 if (myPB == nil || MemError() != noErr) {                            /* we don't reuse the same paramBlock in */
  563.                     DebugPrint("\pNo memory for a new paramBlockRec!");                /* the ioCompletion routine. */
  564.                     theErr = memFullErr;
  565.                 }
  566.                 else {
  567.                     myPB->myA5 = SetCurrentA5 ();
  568.                     myPB->theSoundInfo = theSoundInfo;
  569.                     myIOCompletion = NewIOCompletionProc (ASoundFileCallBack);
  570.                     myPB->pb.ioParam.ioCompletion = myIOCompletion;
  571.                     myPB->pb.ioParam.ioVRefNum = theSoundInfo->vRefNum;
  572.                     myPB->pb.ioParam.ioRefNum = theSoundInfo->refNum;
  573.                     myPB->pb.ioParam.ioPosMode = fsFromStart | noCacheMask;                /* Set the noCacheBit since we probably won't be reading this again */
  574.                     doubleBuffer->dbUserInfo[kPBPtr] = (long)myPB;
  575.  
  576.                     theSoundInfo->doubleHeader.dbhBufferPtr[i] = doubleBuffer;
  577.                 }
  578.             }
  579.         }
  580.         else {
  581.             doubleBuffer = theSoundInfo->doubleHeader.dbhBufferPtr[i];
  582.         }
  583.  
  584.         ASoundDoubleBackProc (theSoundInfo->chan, doubleBuffer);    /* prime the buffers */
  585.  
  586.     }
  587.  
  588.     if (theErr != noErr) {
  589.         DebugPrint ("\pError in ASoundPrimeBuffers");
  590.         for (i = kInit; i <= kOne; ++i) {
  591.             if (!theSoundInfo->doubleHeader.dbhBufferPtr[i]) {
  592.                 DisposePtr ((Ptr)myIOCompletion);
  593.                 DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]->dbUserInfo[kSndInfoPtr]);
  594.                 DisposePtr ((Ptr)theSoundInfo->doubleHeader.dbhBufferPtr[i]);
  595.             }
  596.         }
  597.     }
  598.  
  599.     return theErr;
  600. }
  601.  
  602. /* This routine is used to calculate where to put the SFGetFile Dialog */
  603. /*-----------------------------------------------------------------------*/
  604.         Rect    GetMainScreenRect        (void)
  605. /*-----------------------------------------------------------------------*/
  606. {
  607.     GDHandle    mainDevice;
  608.     GrafPtr        mainPort;
  609.     Rect        returnRect;
  610.     long        response;
  611.     
  612.     Gestalt (gestaltQuickdrawVersion, &response);
  613.     
  614.     if (response == gestaltOriginalQD) {
  615.         GetWMgrPort (&mainPort);
  616.         returnRect = mainPort->portRect;
  617.     }
  618.     else {
  619.         mainDevice = GetMainDevice();
  620.         returnRect = (*mainDevice)->gdRect;
  621.     }
  622.  
  623.     return returnRect;
  624. }
  625.